package com.ilxqx.framework.system.validator;

import com.google.common.collect.Lists;
import com.ilxqx.framework.system.validator.anno.MultiFieldsUnique;
import com.ilxqx.framework.util.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;

import javax.persistence.Id;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 记录是否唯一验证器
 * @author venus
 */
public class MultiFieldsUniqueValidator implements ConstraintValidator<MultiFieldsUnique, Object> {

	private String serviceName;

	private Class<?> service;

	private String method;

	private String[] fields;

	/**
	 * Initializes the validator in preparation for
	 * {@link #isValid(Object, ConstraintValidatorContext)} calls.
	 * The constraint annotation for a given constraint declaration
	 * is passed.
	 * <p>
	 * This method is guaranteed to be called before any use of this instance for
	 * validation.
	 * <p>
	 * The default implementation is a no-op.
	 *
	 * @param constraintAnnotation annotation instance for a given constraint declaration
	 */
	@Override
	public void initialize(MultiFieldsUnique constraintAnnotation) {
		this.serviceName = constraintAnnotation.serviceName();
		this.service = constraintAnnotation.service();
		this.method = constraintAnnotation.method();
		this.fields = constraintAnnotation.fields();
	}

	/**
	 * Implements the validation logic.
	 * The state of {@code value} must not be altered.
	 * <p>
	 * This method can be accessed concurrently, thread-safety must be ensured
	 * by the implementation.
	 *
	 * @param value   object to validate
	 * @param context context in which the constraint is evaluated
	 * @return {@code false} if {@code value} does not pass the constraint
	 */
	@Override
	public boolean isValid(Object value, ConstraintValidatorContext context) {
		Object instance;
		if (StringUtils.isNotBlank(this.serviceName)) {
			instance = SpringUtils.getBean(this.serviceName, this.service);
		} else {
			instance = SpringUtils.getBean(this.service);
		}
		// 查找Unique字段
        List<Field> fieldList = Lists.newArrayList();
        for (String field : this.fields) {
            Field member = ReflectionUtils.findField(value.getClass(), field);
            if (member == null) {
                return false;
            }
            fieldList.add(member);
        }
		// 调用service的判断方法
		Method method = ReflectionUtils.findMethod(this.service, this.method, fieldList.stream().map(Field::getType).toArray(Class<?>[]::new));
		if (method == null) {
			// 找不到方法
			return false;
		}
		Object result = ReflectionUtils.invokeMethod(method, instance, fieldList.stream().map(field -> com.ilxqx.framework.system.util.ReflectionUtils.getFieldValue(field, value)).toArray());
		if (result == null) {
			return true;
		}
		Object pk = com.ilxqx.framework.system.util.ReflectionUtils.getFormDataPk(value);
		if (pk == null) {
			return false;
		}
		List<Field> entityPk = com.ilxqx.framework.system.util.ReflectionUtils.getAnnotatedFields(value.getClass(), Id.class);
		if (entityPk.isEmpty()) {
			return false;
		}
		return Objects.equals(pk, com.ilxqx.framework.system.util.ReflectionUtils.getFieldValue(entityPk.get(0), result));
	}

}
